Skip to content

Comments

Rework error handling#813

Merged
craigbarratt merged 9 commits intocustom-components:masterfrom
dmamelin:rework-error-handling
Feb 20, 2026
Merged

Rework error handling#813
craigbarratt merged 9 commits intocustom-components:masterfrom
dmamelin:rework-error-handling

Conversation

@dmamelin
Copy link
Contributor

@dmamelin dmamelin commented Feb 13, 2026

This is a major change in Pyscript core. Please review it very carefully, especially ast_try, ast_raise, and EvalFunc.call.
Originally this was one large change, but I split it into smaller commits to make it easier to review. Each commit is consistent. Everything works and the tests pass.

Main idea:

  • we shouldn't try to reimplement python’s exception system - we just need to avoid interfering with it
  • exceptions should not be caught in the core and passed around; they should be handled at entry points
  • exceptions should always be raised normally, and only wrapped in finally where needed to restore context
  • formatting user messages should be separated from exception handling

Exception logging:

Initially, I planned to keep the old behavior and show only a single frame where the error occurred, but I ended up implementing a full traceback 🙂

#modules/mod_test.py
def problem():
    return 0 / 0

async def no_problem(callback):
    return 0 + callback()

#test.py
from mod_test import no_problem, problem

def func1(x):
    return x + func2(x)

@pyscript_compile
async def func2(x):
    return x + await no_problem(func3)

def func3():
    return 3 + problem()

@time_trigger
def start():
    try:
        func1(1)
    except ZeroDivisionError:
        del x

#console output: 
2026-02-13 02:38:36.622 ERROR (MainThread) [custom_components.pyscript.file.test.start]
  File "/config/pyscript/test.py", line 22, in file.test.start
    func1(1)
    ~~~~~^^^
  File "/config/pyscript/test.py", line 7, in func1
    return x + func2(x)
               ~~~~~^^^
  File "/config/pyscript/test.py", line 12, in func2
    return x + await no_problem(func3)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/pyscript/modules/mod_test.py", line 9, in no_problem
    return 0 + callback()
               ~~~~~~~~^^
  File "/config/pyscript/test.py", line 16, in func3
    return 3 + problem()
               ~~~~~~~^^
  File "/config/pyscript/modules/mod_test.py", line 5, in problem
    return 0 / 0
           ~~^~~
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

  File "/config/custom_components/pyscript/trigger.py", line 1394, in do_func_call
    await ast_ctx.call_func(func, None, **kwargs)
  File "/config/pyscript/test.py", line 24, in start
    del x
NameError: name 'x' is not defined

EvalExceptionFormatter

  • standard traceback mechanisms are used, with adjustments for user code
  • iterates over the traceback and extracts all necessary data from local variables. lineno and col_offset are taken from ast.expr / ast.stmt, which results in more precise error locations
  • it isn't perfect, but it's not core functionality and doesn't affect code execution. It can be refined over time
  • there are some quirks in the core regarding context names, file names, and their source text. These are handled in formatter, but I plan to clean this up properly in the future

Tests:

There are many changes because the new mechanism closely matches native python behavior and is more precise.
Please pay attention to the last commit with exception chaining - it tests pyscript using pyscript itself.

@ALERTua
Copy link
Contributor

ALERTua commented Feb 13, 2026

you are the best!

@dmamelin
Copy link
Contributor Author

@craigbarratt If the overall direction doesn't feel right, I'm open to rethinking the main idea and exploring a different approach.

@craigbarratt
Copy link
Member

Sorry about the delay in replying - I'm traveling.

This looks excellent - a much better approach to let the native exception system do its job.

I'm happy to merge this now, or should we wait a couple of weeks until we merge #795?

@dmamelin
Copy link
Contributor Author

dmamelin commented Feb 20, 2026

I think it makes sense to merge this now. After that, I'll rebase/merge #795 and immediately apply the necessary architectural updates there.

I also plan to make a couple of small follow-up changes after this PR.

For #795, I can either merge it as a separate PR with a single commit to keep the history clean, or preserve the full commit history - whichever you prefer. What do you think?

Thanks for reviewing this while traveling - really appreciate it.

@craigbarratt craigbarratt merged commit 5d9fba4 into custom-components:master Feb 20, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants